package cn.jsu.oj.dispatchServer.satellite.util;

import org.springframework.core.io.Resource;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 注解扫描工具
 *
 * @author atonic、shan
 * @date 2022/05/31
 */
public class AnnScanUtil {

    /**
     * ClassLoader扫描根路径
     */
    public final static String FILE_NAME;

    static {
        FILE_NAME = Objects.requireNonNull(AnnScanUtil.class.getClassLoader().getResource("")).getFile();
    }

    /**
     * 扫描包
     *
     * @param pkg      包
     * @param classAnn 注解类模板
     * @return {@link List }<{@link Class }<{@link ? }>>
     */
    public static List<Class<?>> scanPackage(String pkg, Class<? extends Annotation> classAnn) {
        List<Class<?>> list = new ArrayList<>();
        try {
            Resource[] resources = ClassPathFileUtil.getClassFileResourcesByPackageName(pkg);
            for (Resource resource : resources) {
                if (!ClassPathFileUtil.isDirectory(resource)) {
                    String filePath = resource.getURL().getFile().substring(FILE_NAME.length()).replace(".class", "");
                    Class<?> c = Class.forName(filePath.replaceAll("/", "."));
                    if (classAnn != null) {
                        if (c.getAnnotation(classAnn) != null) {
                            list.add(c);
                        }
                    } else {
                        list.add(c);
                    }
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 扫描方法
     *
     * @param pkg       包
     * @param classAnn  注解类模板
     * @param methodAnn 方法类模板
     * @return {@link List }<{@link Method }>
     */
    public static List<Method> scanMethod(String pkg, Class<? extends Annotation> classAnn, Class<? extends Annotation> methodAnn) {
        List<Method> methodList = new ArrayList<>();
        List<Class<?>> classList = scanPackage(pkg, classAnn);
        for (Class<?> cla : classList) {
            Method[] methods = cla.getDeclaredMethods();
            for (Method method : methods) {
                if (method.getAnnotation(methodAnn) != null) {
                    methodList.add(method);
                }
            }
        }
        return methodList;
    }
}
